package ch.ti.bfh.app.loodel.internal;

import ch.ti.bfh.app.loodel.domain.learningEvent.LearningEvent;
import ch.ti.bfh.app.loodel.domain.learningEvent.LearningEventRepository;
import ch.ti.bfh.app.loodel.domain.member.Member;
import ch.ti.bfh.app.loodel.domain.timeslot.TimeSlot;
import ch.ti.bfh.app.loodel.domain.timeslot.TimeSlotRepository;
import ch.ti.bfh.app.loodel.domain.timeslotvote.TimeSlotVote;
import ch.ti.bfh.app.loodel.domain.timeslotvote.TimeSlotVoteRepository;
import ch.ti.bfh.app.loodel.internal.security.InternalUserContext;
import ch.ti.bfh.app.loodel.service.vote.AllMembersTimeSlotVotesData;
import ch.ti.bfh.app.loodel.service.vote.CurrentMemberTimeSlotVoteData;
import ch.ti.bfh.app.loodel.service.vote.LearningEventVoteData;
import ch.ti.bfh.app.loodel.service.vote.LearningEventVoteService;
import org.apache.commons.lang.Validate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

@Service
@Transactional
public class DefaultLearningEventVoteService implements LearningEventVoteService {

    private final LearningEventRepository learningEventRepository;

    private final TimeSlotVoteRepository timeSlotVoteRepository;

    private final TimeSlotRepository timeSlotRepository;

    private final InternalUserContext internalUserContext;


    @Inject
    public DefaultLearningEventVoteService(LearningEventRepository learningEventRepository, TimeSlotVoteRepository timeSlotVoteRepository, TimeSlotRepository timeSlotRepository, InternalUserContext internalUserContext) {
        this.learningEventRepository = learningEventRepository;
        this.timeSlotVoteRepository = timeSlotVoteRepository;
        this.timeSlotRepository = timeSlotRepository;
        this.internalUserContext = internalUserContext;
    }

    @Override
    public int giveYourTimeSlotVote(Long timeSlotId) {
        TimeSlot timeSlot = timeSlotRepository.getOne(timeSlotId);
        Member currentMember = internalUserContext.getCurrentMember();
        TimeSlotVote existingTimeSlotVote = timeSlotVoteRepository.findByTimeSlotIdAndMemberId(timeSlotId, currentMember.getId());
        if (existingTimeSlotVote != null) {
            throw new IllegalArgumentException("There is already a Time Slot Vote for TimeSlot: '" + timeSlotId + "' and Member: '" + currentMember + "'\"");
        }
        TimeSlotVote timeSlotVote = new TimeSlotVote(timeSlot, currentMember);
        timeSlot.addTimeSlotVote(timeSlotVote);
        timeSlotVoteRepository.save(timeSlotVote);
        return timeSlot.getVoteCount();
    }

    @Override
    public int removeYourTimeSlotVote(Long timeSlotId) {
        TimeSlot timeSlot = timeSlotRepository.getOne(timeSlotId);
        Member currentMember = internalUserContext.getCurrentMember();
        TimeSlotVote timeSlotVote = timeSlotVoteRepository.findByTimeSlotIdAndMemberId(timeSlotId, currentMember.getId());
        Validate.notNull(timeSlotVote, "No Time Slot Vote has been set for TimeSlot: '" + timeSlotId + "' and Member: '" + currentMember + "'");
        timeSlot.removeTimeSlotVote(timeSlotVote);
        timeSlotVoteRepository.delete(timeSlotVote);
        return timeSlot.getVoteCount();
    }


    @Override
    public LearningEventVoteData getLearningEventVoteData(String learningEventId) {
        List<Member> allVotedMembersForLearningEvent = timeSlotVoteRepository.findAllVotedMembersForLearningEvent(learningEventId);
        LearningEventVoteData learningEventVoteData = LearningEventAssembler.getLearningEventVoteData(learningEventRepository.getOne(learningEventId), allVotedMembersForLearningEvent.size());
        return learningEventVoteData;
    }

    @Override
    public List<CurrentMemberTimeSlotVoteData> getCurrentMemberTimeSlotVotes(String learningEventId) {
        LearningEvent learningEvent = learningEventRepository.getOne(learningEventId);
        Member currentMember = internalUserContext.getCurrentMember();
        List<CurrentMemberTimeSlotVoteData> list = new ArrayList<CurrentMemberTimeSlotVoteData>();
        Set<TimeSlot> timeSlots = learningEvent.getTimeSlots();
        for (TimeSlot timeSlot : timeSlots) {
            CurrentMemberTimeSlotVoteData currentMemberTimeSlotVoteData = getShowTimeSlotVoteDetailData(timeSlot, currentMember);
            list.add(currentMemberTimeSlotVoteData);
        }
        return list;
    }

    @Override
    public CurrentMemberTimeSlotVoteData getCurrentMemberTimeSlotVote(Long timeSlotId) {
        TimeSlot timeSlot = timeSlotRepository.getOne(timeSlotId);
        Member currentMember = internalUserContext.getCurrentMember();
        CurrentMemberTimeSlotVoteData currentMemberTimeSlotVoteData = getShowTimeSlotVoteDetailData(timeSlot, currentMember);
        return currentMemberTimeSlotVoteData;
    }

    @Override
    public List<AllMembersTimeSlotVotesData> getAllMembersTimeSlotVotes(String learningEventId) {
        LearningEvent learningEvent = learningEventRepository.getOne(learningEventId);
        Member currentMember = internalUserContext.getCurrentMember();
        List<AllMembersTimeSlotVotesData> list = new ArrayList<AllMembersTimeSlotVotesData>();
        Set<TimeSlot> timeSlots = learningEvent.getTimeSlots();
        for (TimeSlot timeSlot : timeSlots) {
            TimeSlotVote currentMemberTimeSlotVote = timeSlotVoteRepository.findByTimeSlotIdAndMemberId(timeSlot.getId(), currentMember.getId());
            List<TimeSlotVote> timeSlotVoteList = timeSlotVoteRepository.findTimeSlotVotesByTimeSlot_Id(timeSlot.getId());
            AllMembersTimeSlotVotesData allMembersTimeSlotVotesData = TimeSlotVoteAssembler.buildAllMembersTimeSlotVoteData(timeSlot, currentMemberTimeSlotVote != null, timeSlotVoteList);
            list.add(allMembersTimeSlotVotesData);
        }
        return list;
    }

    @Override
    public AllMembersTimeSlotVotesData getAllMembersTimeSlotVotesData(Long timeSlotId) {
        throw new UnsupportedOperationException();
    }


    private CurrentMemberTimeSlotVoteData getShowTimeSlotVoteDetailData(TimeSlot timeSlot, Member currentMember) {
        TimeSlotVote existingTimeSlotVote = timeSlotVoteRepository.findByTimeSlotIdAndMemberId(timeSlot.getId(), currentMember.getId());
        boolean hasCurrentMemberVoted = false;
        if (existingTimeSlotVote != null) {
            hasCurrentMemberVoted = true;
        }
        return TimeSlotVoteAssembler.getCurrentMemberTimeSlotVoteData(timeSlot, hasCurrentMemberVoted);
    }
}
